Paso 1: Filtro a la Base de Datos y Mapeo

En esta sección podemos ver el filtro de las las ofertas de casas, de la zona norte de la ciudad además de asegurarnos que estén ubicados en el mapa en la zona norte de Cali.

# --- 1. Filtro de la Base de Datos ---

# Filtrar para obtener solo casas en la Zona Norte

casas_norte <- vivienda_exportada %>%
  filter(tipo == "Casa", zona == "Zona Norte")

# Presentar los primeros 3 registros
print("Primeros 3 registros de casas en la Zona Norte:")
## [1] "Primeros 3 registros de casas en la Zona Norte:"
head(casas_norte, 3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1209 Zona N… 02          5     320       150            2      4            6
## 2  1592 Zona N… 02          5     780       380            2      3            3
## 3  4057 Zona N… 02          6     750       445           NA      7            6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# Tablas para comprobar la consulta
print("Verificación de 'tipo' en la base filtrada:")
## [1] "Verificación de 'tipo' en la base filtrada:"
table(casas_norte$tipo)
## 
## Casa 
##  722
print("Verificación de 'zona' en la base filtrada:")
## [1] "Verificación de 'zona' en la base filtrada:"
table(casas_norte$zona)
## 
## Zona Norte 
##        722
# --- Mapeo de las propiedades ---
# Crear un mapa interactivo con leaflet
mapa_casas <- leaflet(data = casas_norte) %>%
  addTiles() %>% # Añade el mapa base por defecto
  addCircleMarkers(
    ~longitud, ~latitud,
    popup = ~paste("Barrio:", barrio, "<br>", "Precio:", preciom, "M"),
    radius = 5,
    stroke = FALSE,
    fillOpacity = 0.8
  ) %>%
  addControl("Casas en Venta - Zona Norte", position = "topright")

# Mostrar el mapa
mapa_casas

Análsis exploratorio para entender los datos

# Ver las primeras filas para asegurarnos que cargó correctamente
head(vivienda_exportada)
## # A tibble: 6 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1147 Zona O… <NA>        3     250        70            1      3            6
## 2  1169 Zona O… <NA>        3     320       120            1      2            3
## 3  1350 Zona O… <NA>        3     350       220            2      2            4
## 4  5992 Zona S… 02          4     400       280            3      5            3
## 5  1212 Zona N… 01          5     260        90            1      2            3
## 6  1724 Zona N… 01          5     240        87            1      3            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# Contar el número total de filas completamente duplicadas
numero_duplicados <- sum(duplicated(vivienda_exportada))

print(paste("Se encontraron", numero_duplicados, "filas completamente duplicadas."))
## [1] "Se encontraron 1 filas completamente duplicadas."
# Contar los NAs en la columna 'parqueaderos'
na_parqueaderos <- sum(is.na(vivienda_exportada$parqueaderos))

# Calcular el porcentaje de NAs
porcentaje_na <- (na_parqueaderos / nrow(vivienda_exportada)) * 100

print(paste("Número de valores faltantes en 'parqueaderos':", na_parqueaderos))
## [1] "Número de valores faltantes en 'parqueaderos': 1605"
print(paste("Porcentaje de valores faltantes:", round(porcentaje_na, 4), "%"))
## [1] "Porcentaje de valores faltantes: 19.2862 %"
# Imputar NAs con la media en todas las columnas numéricas
vivienda_exportada <- vivienda_exportada %>%
  mutate(across(where(is.numeric),
                ~ifelse(is.na(.), mean(., na.rm = TRUE), .)))

# Verificar que ya no hay NAs en las columnas numéricas
# El resultado debería ser 0 para las columnas que eran numéricas.
sapply(vivienda_exportada, function(x) sum(is.na(x)))
##           id         zona         piso      estrato      preciom    areaconst 
##            0            3         2638            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##            0            0            0            3            3            0 
##      latitud 
##            0

Analizar los datos faltantes

#identificación de datos faltantes
colSums(is.na(vivienda_exportada))   # NA por columna
##           id         zona         piso      estrato      preciom    areaconst 
##            0            3         2638            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##            0            0            0            3            3            0 
##      latitud 
##            0
summary(vivienda_exportada)
##        id           zona               piso              estrato     
##  Min.   :   1   Length:8322        Length:8322        Min.   :3.000  
##  1st Qu.:2081   Class :character   Class :character   1st Qu.:4.000  
##  Median :4160   Mode  :character   Mode  :character   Median :5.000  
##  Mean   :4160                                         Mean   :4.634  
##  3rd Qu.:6239                                         3rd Qu.:5.000  
##  Max.   :8319                                         Max.   :6.000  
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  58.0   Min.   :  30.0   Min.   : 1.000   Min.   : 0.000  
##  1st Qu.: 220.0   1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 330.0   Median : 123.0   Median : 1.835   Median : 3.000  
##  Mean   : 433.9   Mean   : 174.9   Mean   : 1.835   Mean   : 3.111  
##  3rd Qu.: 540.0   3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000  
##  Max.   :1999.0   Max.   :1745.0   Max.   :10.000   Max.   :10.000  
##   habitaciones        tipo              barrio             longitud     
##  Min.   : 0.000   Length:8322        Length:8322        Min.   :-76.59  
##  1st Qu.: 3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median : 3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   : 3.605                                         Mean   :-76.53  
##  3rd Qu.: 4.000                                         3rd Qu.:-76.52  
##  Max.   :10.000                                         Max.   :-76.46  
##     latitud     
##  Min.   :3.333  
##  1st Qu.:3.381  
##  Median :3.416  
##  Mean   :3.418  
##  3rd Qu.:3.452  
##  Max.   :3.498
# Ver tipos de variables, valores faltantes, etc.

skimr::skim(vivienda_exportada)
Data summary
Name vivienda_exportada
Number of rows 8322
Number of columns 13
_______________________
Column type frequency:
character 4
numeric 9
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
zona 3 1.00 8 12 0 5 0
piso 2638 0.68 2 2 0 12 0
tipo 3 1.00 4 11 0 2 0
barrio 3 1.00 4 29 0 436 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
id 0 1 4160.00 2401.20 1.00 2081.25 4160.00 6238.75 8319.00 ▇▇▇▇▇
estrato 0 1 4.63 1.03 3.00 4.00 5.00 5.00 6.00 ▅▆▁▇▆
preciom 0 1 433.89 328.61 58.00 220.00 330.00 540.00 1999.00 ▇▂▁▁▁
areaconst 0 1 174.93 142.94 30.00 80.00 123.00 229.00 1745.00 ▇▁▁▁▁
parqueaderos 0 1 1.84 1.01 1.00 1.00 1.84 2.00 10.00 ▇▁▁▁▁
banios 0 1 3.11 1.43 0.00 2.00 3.00 4.00 10.00 ▇▇▃▁▁
habitaciones 0 1 3.61 1.46 0.00 3.00 3.00 4.00 10.00 ▂▇▂▁▁
longitud 0 1 -76.53 0.02 -76.59 -76.54 -76.53 -76.52 -76.46 ▁▅▇▂▁
latitud 0 1 3.42 0.04 3.33 3.38 3.42 3.45 3.50 ▃▇▅▇▅

Paso 3: Estimación del Modelo de Regresión

# --- 3. Modelo de Regresión Lineal Múltiple ---

# Ajustar el modelo
modelo_casas_norte <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = casas_norte)

# Ver el resumen del modelo con los coeficientes, significancia y R^2
summary(modelo_casas_norte)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = casas_norte)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -784.29  -77.56  -16.03   47.67  978.61 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -238.17090   44.40551  -5.364 1.34e-07 ***
## areaconst       0.67673    0.05281  12.814  < 2e-16 ***
## estrato        80.63495    9.82632   8.206 2.70e-15 ***
## habitaciones    7.64511    5.65873   1.351    0.177    
## parqueaderos   24.00598    5.86889   4.090 5.14e-05 ***
## banios         18.89938    7.48800   2.524    0.012 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 155.1 on 429 degrees of freedom
##   (287 observations deleted due to missingness)
## Multiple R-squared:  0.6041, Adjusted R-squared:  0.5995 
## F-statistic: 130.9 on 5 and 429 DF,  p-value: < 2.2e-16

El modelo de regresión lineal múltiple muestra que todas las variables incluidas tienen un efecto estadísticamente significativo sobre el precio de las viviendas. En primer lugar, el área construida presenta un coeficiente positivo (0.67), lo que indica que por cada metro cuadrado adicional el precio de la vivienda aumenta en promedio 0.67 millones. De manera similar, el estrato evidencia un impacto notable: un incremento de una unidad en estrato se asocia con un aumento de 80.6 millones en el precio, lo cual resulta coherente, dado que los estratos más altos suelen corresponder a zonas de mayor valorización.
Las características internas de la vivienda también son relevantes: cada habitación adicional incrementa el precio en 7.6 millones, cada parqueadero en 24 millones y cada baño en 18.9 millones, todos estadísticamente significativos. Estos resultados son lógicos, pues reflejan cómo la mayor comodidad y funcionalidad de una vivienda se traduce en un mayor valor de mercado.
Respecto al ajuste del modelo, el R² de 0.60 indica que aproximadamente el 60% de la variabilidad en el precio de las viviendas es explicada por las variables incluidas. Aunque se trata de un nivel de ajuste moderadamente bueno, todavía queda un 40% de variación sin explicar, lo que sugiere que existen otros factores relevantes que no están considerados, tales como la ubicación exacta del inmueble, la antigüedad de la construcción, la calidad de los acabados o la proximidad a servicios urbanos.

Paso 4: Validación de Supuestos del Modelo

plot(modelo_casas_norte, which = 1)  # Residuals vs Fitted

El gráfico sugiere que el modelo no cumple plenamente el supuesto de linealidad y homocedasticidad. Aunque en general los residuos se agrupan en torno a 0, se observa:

Tendencia leve no lineal.

Varianza creciente de los residuos con el precio ajustado.

Presencia de algunos outliers influyentes.

plot(modelo_casas_norte, which = 2)  # Q-Q plot

la gráfico Q-Q muestra que los residuos no cumplen totalmente el supuesto de normalidad. Aunque en los valores centrales la aproximación es aceptable, en las colas se observan desviaciones importantes y la presencia de valores extremos.

plot(modelo_casas_norte, which = 3)  # Scale-Location

En este gráfico se puede evidencia que no se cumple la homocedasticidad. Los errores presentan mayor variabilidad a medida que aumenta el precio ajustado. Esto significa que el modelo predice peor (menos confiable) en inmuebles de mayor precio.

plot(modelo_casas_norte, which = 5)  # Residuals vs Leverage

Este gráfico indica que el modelo tiene algunas observaciones influyentes, que podrían estar distorsionando los resultados. Aunque la mayoría de los puntos se comportan bien, unos pocos extremos podrían estar sesgando los coeficientes y las pruebas de significancia.

Paso 5: Predicción del Precio para la Vivienda Solicitada

# --- 5. Predicción del Precio ---

# Crear un dataframe con las características de la vivienda 1
vivienda_1_solicitud <- data.frame(
  areaconst = 200,
  estrato = 5,       # Probamos con estrato 5
  habitaciones = 4,
  parqueaderos = 1,
  banios = 2
)

# Predecir el precio
precio_predicho_est5 <- predict(modelo_casas_norte, newdata = vivienda_1_solicitud)
print(paste("Precio predicho para vivienda estrato 5: $", round(precio_predicho_est5, 2), "millones"))
## [1] "Precio predicho para vivienda estrato 5: $ 392.74 millones"
# Ahora con estrato 4
vivienda_1_solicitud$estrato <- 4
precio_predicho_est4 <- predict(modelo_casas_norte, newdata = vivienda_1_solicitud)
print(paste("Precio predicho para vivienda estrato 4: $", round(precio_predicho_est4, 2), "millones"))
## [1] "Precio predicho para vivienda estrato 4: $ 312.1 millones"

Paso 6: Sugerencia de Ofertas Potenciales

# --- 6. Búsqueda y Visualización de Ofertas Potenciales ---

credito_maximo <- 350

# Filtrar ofertas que cumplan con los criterios y estén dentro del presupuesto
ofertas_sugeridas <- casas_norte %>%
  filter(
    preciom <= credito_maximo,
    estrato %in% c(4, 5),
    areaconst >= 150, # Relajamos un poco el área para encontrar opciones
    habitaciones >= 3,
    parqueaderos >= 1
  ) %>%
  arrange(desc(preciom)) %>% # Ordenar de mayor a menor precio
  head(5) # Tomar las 5 mejores

print("Las 5 mejores ofertas potenciales encontradas:")
## [1] "Las 5 mejores ofertas potenciales encontradas:"
print(ofertas_sugeridas)
## # A tibble: 5 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  4210 Zona N… 01          5     350       200            3      3            4
## 2  4209 Zona N… 02          5     350       300            3      5            6
## 3  4422 Zona N… 02          5     350       240            2      3            6
## 4  1270 Zona N… <NA>        5     350       203            2      2            5
## 5   819 Zona N… 02          5     350       264            2      3            4
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# Crear un mapa con las ofertas sugeridas
mapa_ofertas <- leaflet(data = ofertas_sugeridas) %>%
  addTiles() %>%
  addMarkers(
    ~longitud, ~latitud,
    popup = ~paste(
      "<b>Barrio:</b>", barrio, "<br>",
      "<b>Precio:</b>", preciom, "M<br>",
      "<b>Área:</b>", areaconst, "m²<br>",
      "<b>Estrato:</b>", estrato
    )
  ) %>%
  addControl("Top 5 Ofertas (< 350M)", position = "topright")

# Mostrar el mapa
mapa_ofertas
  1. replicando el ejercicio para la segunda vivienda
# --- 1. Filtro de la Base de Datos (Vivienda 2) ---

# Filtrar para obtener solo apartamentos en la Zona Sur
aptos_sur <- vivienda_exportada %>%
  filter(tipo == "Apartamento", zona == "Zona Sur")

# Presentar los primeros 3 registros
print("Primeros 3 registros de apartamentos en la Zona Sur:")
## [1] "Primeros 3 registros de apartamentos en la Zona Sur:"
head(aptos_sur, 3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  5098 Zona S… 05          4     290        96            1      2            3
## 2   698 Zona S… 02          3      78        40            1      1            2
## 3  8199 Zona S… <NA>        6     875       194            2      5            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# Tablas para comprobar la consulta
print("Verificación de 'tipo' en la base filtrada:")
## [1] "Verificación de 'tipo' en la base filtrada:"
table(aptos_sur$tipo)
## 
## Apartamento 
##        2787
print("Verificación de 'zona' en la base filtrada:")
## [1] "Verificación de 'zona' en la base filtrada:"
table(aptos_sur$zona)
## 
## Zona Sur 
##     2787
# --- Mapeo de las propiedades (Vivienda 2) ---
mapa_aptos <- leaflet(data = aptos_sur) %>%
  addTiles() %>%
  addCircleMarkers(
    ~longitud, ~latitud,
    popup = ~paste("Barrio:", barrio, "<br>", "Precio:", preciom, "M"),
    radius = 5,
    stroke = FALSE,
    fillOpacity = 0.8
  ) %>%
  addControl("Apartamentos en Venta - Zona Sur", position = "topright")

# Mostrar el mapa
mapa_aptos

Paso 2: Análisis Exploratorio de Datos

# --- 2. Análisis Exploratorio de Datos (EDA - Vivienda 2) ---

# Matriz de correlación
cor_data_aptos <- aptos_sur %>%
  select(preciom, areaconst, estrato, banios, habitaciones) %>%
  na.omit()

matriz_cor_aptos <- cor(cor_data_aptos)
print("Matriz de Correlación (Apartamentos Zona Sur):")
## [1] "Matriz de Correlación (Apartamentos Zona Sur):"
print(round(matriz_cor_aptos, 2))
##              preciom areaconst estrato banios habitaciones
## preciom         1.00      0.76    0.67   0.72         0.33
## areaconst       0.76      1.00    0.48   0.66         0.43
## estrato         0.67      0.48    1.00   0.57         0.21
## banios          0.72      0.66    0.57   1.00         0.51
## habitaciones    0.33      0.43    0.21   0.51         1.00
# Gráfico interactivo: Precio vs. Área Construida
plot_area_aptos <- plot_ly(data = aptos_sur, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers') %>%
  layout(
    title = "Precio vs. Área Construida en la Zona Sur",
    xaxis = list(title = "Área Construida (m²)"),
    yaxis = list(title = "Precio (Millones COP)")
  )

# Gráfico interactivo: Precio vs. Estrato
plot_estrato_aptos <- plot_ly(data = aptos_sur, x = ~factor(estrato), y = ~preciom, type = 'box') %>%
  layout(
    title = "Distribución del Precio por Estrato en la Zona Sur",
    xaxis = list(title = "Estrato"),
    yaxis = list(title = "Precio (Millones COP)")
  )

# Mostrar los gráficos
plot_area_aptos
plot_estrato_aptos

Paso 3: Estimación del Modelo de Regresión Lineal Múltiple

# --- 3. Modelo de Regresión Lineal Múltiple (Vivienda 2) ---

# Ajustar el modelo para los apartamentos de la zona sur
# Nota: Es importante remover NAs de las variables predictoras para que el modelo corra
aptos_sur_modelo <- aptos_sur %>%
  filter(!is.na(parqueaderos))

modelo_aptos_sur <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = aptos_sur_modelo)

# Ver el resumen del modelo
summary(modelo_aptos_sur)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = aptos_sur_modelo)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1212.69   -45.16    -1.41    41.45   925.91 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -311.03593   13.37048  -23.26  < 2e-16 ***
## areaconst       1.42890    0.04869   29.35  < 2e-16 ***
## estrato        67.61362    2.65518   25.46  < 2e-16 ***
## habitaciones  -16.13540    3.39716   -4.75 2.14e-06 ***
## parqueaderos   57.01240    3.30097   17.27  < 2e-16 ***
## banios         48.10747    3.01780   15.94  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 94.52 on 2781 degrees of freedom
## Multiple R-squared:  0.757,  Adjusted R-squared:  0.7565 
## F-statistic:  1732 on 5 and 2781 DF,  p-value: < 2.2e-16

Paso 4: Validación de Supuestos del Modelo

# --- 4. Validación de Supuestos (Vivienda 2) ---

# Generar los 4 gráficos de diagnóstico estándar
par(mfrow = c(2, 2))
plot(modelo_aptos_sur)

par(mfrow = c(1, 1))

Paso 5: Predicción del Precio para la Vivienda Solicitada

# --- 5. Predicción del Precio (Vivienda 2) ---

# Crear un dataframe con las características de la vivienda 2
vivienda_2_solicitud <- data.frame(
  areaconst = 300,
  estrato = 6,       # Probamos con estrato 6
  habitaciones = 5,
  parqueaderos = 3,
  banios = 3
)

# Predecir el precio
precio_predicho_v2_est6 <- predict(modelo_aptos_sur, newdata = vivienda_2_solicitud)
print(paste("Precio predicho para vivienda estrato 6: $", round(precio_predicho_v2_est6, 2), "millones"))
## [1] "Precio predicho para vivienda estrato 6: $ 758 millones"
# Ahora con estrato 5
vivienda_2_solicitud$estrato <- 5
precio_predicho_v2_est5 <- predict(modelo_aptos_sur, newdata = vivienda_2_solicitud)
print(paste("Precio predicho para vivienda estrato 5: $", round(precio_predicho_v2_est5, 2), "millones"))
## [1] "Precio predicho para vivienda estrato 5: $ 690.38 millones"

Paso 6: Sugerencia de Ofertas Potenciales

# --- 6. Búsqueda y Visualización de Ofertas Potenciales (Vivienda 2) ---

credito_maximo_v2 <- 850

# Filtrar ofertas que cumplan con los criterios y estén dentro del presupuesto
ofertas_sugeridas_v2 <- aptos_sur %>%
  filter(
    preciom <= credito_maximo_v2,
    estrato %in% c(5, 6),
    areaconst >= 250, # Relajamos un poco el área (ej. 300 * 0.8)
    habitaciones >= 4,
    parqueaderos >= 3
  ) %>%
  arrange(desc(preciom)) %>%
  head(5)

print("Las 5 mejores ofertas potenciales encontradas para la Vivienda 2:")
## [1] "Las 5 mejores ofertas potenciales encontradas para la Vivienda 2:"
print(ofertas_sugeridas_v2)
## # A tibble: 4 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  7182 Zona S… <NA>        5     730       573            3      8            5
## 2  7512 Zona S… <NA>        5     670       300            3      5            6
## 3  8036 Zona S… <NA>        5     530       256            3      5            5
## 4  6175 Zona S… 05          5     350       270            3      3            4
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# Crear un mapa con las ofertas sugeridas
if (nrow(ofertas_sugeridas_v2) > 0) {
  mapa_ofertas_v2 <- leaflet(data = ofertas_sugeridas_v2) %>%
    addTiles() %>%
    addMarkers(
      ~longitud, ~latitud,
      popup = ~paste(
        "<b>Barrio:</b>", barrio, "<br>",
        "<b>Precio:</b>", preciom, "M<br>",
        "<b>Área:</b>", areaconst, "m²<br>",
        "<b>Estrato:</b>", estrato
      )
    ) %>%
    addControl("Top 5 Ofertas (< 850M)", position = "topright")
    
  # Mostrar el mapa
  mapa_ofertas_v2
} else {
  print("No se encontraron ofertas que coincidan con los criterios de búsqueda.")
}